﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MP3Ganizer.BusinessObject.Infos;
using MP3Ganizer.BusinessObject.Hierarchy;
using MP3Ganizer.BusinessObject.Classification;

namespace MP3Ganizer.BusinessObject.Services.Classification
{
    public class ClassificationService : MP3Ganizer.BusinessObject.Services.Classification.IClassificationService
    {
        Dictionary<CoupleOfString, double> _percentagesMatching;
        public ClassificationService()
        {
            _percentagesMatching = new Dictionary<CoupleOfString, double>();
        }

        public IEnumerable<IHierarchy> TranslateInfosToHierarchy(IEnumerable<MP3Infos> iEnumerable)
        {
            return iEnumerable.OrderBy(t => t.TrackNumber).Select(file => new FileModel(file.Title, file));
        }
        public IEnumerable<IFolderModel> ClassifyByArtists(IEnumerable<MP3Infos> iEnumerable)
        {
            return iEnumerable.GroupBy(info => GetArtistListFromMP3Info(info))
                .OrderBy(t => t.Key)
                .Select(group => new FolderModel(group.Key, group
                    .GroupBy(child => child.Album)
                    .OrderBy(al=>al.Key)
                    .Select(groupChild => new FolderModel(groupChild.Key, groupChild
                        .Select(file => new FileModel(file.Title, file))
                        .OrderBy(t=>t.Infos.TrackNumber)
                    , HierarchyItemType.Album
                        )),HierarchyItemType.Artist));
        }
        public IEnumerable<IFolderModel> ClassifyByAlbum(IEnumerable<MP3Infos> iEnumerable)
        {
            return iEnumerable.GroupBy(info => info.Album)
                .OrderBy(t => t.Key)
                .Select(group => new FolderModel(group.Key, group
                    .GroupBy(child => GetArtistListFromMP3Info(child))
                    .OrderBy(t => t.Key)
                    .Select(groupChild => new FolderModel(groupChild.Key, groupChild
                         .Select(file => new FileModel(file.Title, file))
                         .OrderBy(t=>t.Label)
                    ,HierarchyItemType.Artist     
                         )),HierarchyItemType.Album));
        }
        public IEnumerable<IFolderModel> ClassifyByDirectory(IEnumerable<MP3Infos> iEnumerable)
        {
            return iEnumerable.GroupBy(info => GetDirectoryPathFromMP3Info(info))
                .OrderBy(t => t.Key)
                .Select(directory => new FolderModel(directory.Key, directory
                         .Select(file => new FileModel(file.Title, file))
                         .OrderBy(t => t.Label)
                         ,HierarchyItemType.Folder));
        }

        private string GetArtistListFromMP3Info(MP3Infos info)
        {
            if (info.Artists == null)
                return "";
            return string.Join(", ", info.Artists.OrderBy(s => s).ToArray());
        }
        private string GetDirectoryPathFromMP3Info(MP3Infos info)
        {

            return System.IO.Path.GetDirectoryName(info.SourcePath);
        }

        

        public double GetPercentageOfString(string first, string second)
        {
            CoupleOfString current = new CoupleOfString(first, second);
            double percentage;
            if (_percentagesMatching.TryGetValue(current, out percentage))
            {
                return percentage;
            }
            else
            {
                percentage = CalculatePercentageMatching(first, second);
                _percentagesMatching.Add(current, percentage);
                return percentage;
            }
        }

        /// <summary>
        /// Compute the distance between two strings.
        /// </summary>
        private int Compute(string s, string t)
        {
            int n = s.Length;
            int m = t.Length;
            int[,] d = new int[n + 1, m + 1];

            // Step 1
            if (n == 0)
            {
                return m;
            }

            if (m == 0)
            {
                return n;
            }

            // Step 2
            for (int i = 0; i <= n; d[i, 0] = i++)
            {
            }

            for (int j = 0; j <= m; d[0, j] = j++)
            {
            }

            // Step 3
            for (int i = 1; i <= n; i++)
            {
                //Step 4
                for (int j = 1; j <= m; j++)
                {
                    // Step 5
                    int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;

                    // Step 6
                    d[i, j] = Math.Min(
                        Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
                        d[i - 1, j - 1] + cost);
                }
            }
            // Step 7
            return d[n, m];
        }
        private double CalculatePercentageMatching(String s1, String s2)
        {
            if ((s1 == null) || (s2 == null)) return 0;

            double dis = Compute(s1.ToLower(), s2.ToLower());
            double maxLen = s1.Length;
            if (maxLen < s2.Length)
                maxLen = s2.Length;
            if (maxLen == 0)
                return 100;
            else return (1 - dis / maxLen) * 100;
        }
    }
}
